import json
import re

from QQLoginTool.QQtool import OAuthQQ
from django.conf import settings
from django.contrib.auth import login
from django.http import JsonResponse
from django.views import View
from django_redis import get_redis_connection

from apps.carts.utils import merge_cart_cookie_to_redis
from apps.oauth.models import OAuthQQUser
from apps.users.models import User
from meiduo_mall.utils.secret import SecretOauth


class QQURLView(View):

    def get(self, request):

        # 1:登陆成功之后回哪个网页？
        next = request.GET.get('next')

        #2:创建QQ认证的实例化对象
        oauth = OAuthQQ(
            # 1:用户企业的APPID
            client_id= settings.QQ_CLIENT_ID,
            # 2：用户企业的APP key
            client_secret= settings.QQ_CLIENT_SECRET,
            # 3:用户获取code后，请求的链接
            redirect_uri= settings.QQ_REDIRECT_URI,
            # 4:用户完整登陆完成之后定向到首页
            state=next,
        )

        # 3:获取扫码登陆页面
        login_url = oauth.get_qq_url()

        return JsonResponse({'code': 0, 'errmsg': 'OK', 'login_url': login_url})


class QQUserView(View):

    def get(self, request):
        # 1:获取参数---获取code
        code = request.GET.get("code")

        # 2:校验参数 ---验证参数是否存在
        if not code:
            return JsonResponse({
                "code": 400,
                "errmsg": "参数缺失",
            })

        # 3:数据处理---根据code获取access_token,再根据access_token获取openid

        # 3.1：创建QQ认证的实例化对象
        oauth = OAuthQQ(
            # 1:用户企业的APPID
            client_id=settings.QQ_CLIENT_ID,
            # 2：用户企业的APP key
            client_secret=settings.QQ_CLIENT_SECRET,
            # 3:用户获取code后，请求的链接
            redirect_uri=settings.QQ_REDIRECT_URI,
            # 4:用户完整登陆完成之后定向到首页
            state=next,
        )

        try:
            # 3.2： 使用认证对象获取access_token
            access_token = oauth.get_access_token(code)

            # 3.3 : 使用qq返回的access_token 获取openid
            openid = oauth.get_open_id(access_token)

        except Exception as e:
            # 如果获取不到用户的openid
            print(e)
            return JsonResponse({
                "code": 400,
                "errmsg" : "获取用户的qq信息失败",
            }, status=400)

        # 此处也就是说：获取到了用户的openid.
        # 情况一：如果用户的openid 在数据库中存在，说明之前用户已经绑定了。
        # 情况二：如果用户的openid,在数据库不存在，让用户再次填写一个页面。
        # 2.1 ： 如果填写信息在数据库存在，绑定用户的openid.
        # 2.2 : 如果填写的信息在数据库中不存在,新建用户,写入数据库.

        try:
            # 定义qq登陆的模型类对象获取数据库中的用户对象
            oauth_qq = OAuthQQUser.objects.get(openid=openid)
        except Exception as e:
            # 如果用户没有绑定过用户信息
            # 对openid进行加密，然后返回给用户
            access_token = SecretOauth().dumps({'openid':openid})

            return JsonResponse({'code': 300, 'errmsg': 'ok', 'access_token': access_token})

        else:
            # 用户确实绑定了，接下来要干啥呢？
            # 1：获取用户对象
            user = oauth_qq.user
            # 2：状态保持
            login(request, user)

            # 构建响应：用户username加入cookie
            response = JsonResponse({
                "code": 0,
                "errmsg" : "ok",
            })

            response.set_cookie("username",user.username, max_age=3600*24*14)


            request.user = oauth_qq.user
            return merge_cart_cookie_to_redis(request, response)



    def post(self, request):

        # 1:获取参数
        data_dict = json.loads(request.body.decode())

        mobile = data_dict.get("mobile")
        password = data_dict.get("password")
        # 验证码
        sms_code_client = data_dict.get("sms_code")
        # 用户的openid字段
        access_token = data_dict.get("access_token")

        # 2:校验参数
        # 必要性校验：手机号，密码，验证码必填，如果用户没有注册过，则没有openid,所以aeecss_token不是必须的

        if not all([mobile,password,sms_code_client]):
            return JsonResponse({
                'code': 400,
                'errmsg': "参数缺失"
            },status=400)

        # 判断手机号是否合法：
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                          'errmsg': '请输入正确的手机号码'})

        # 判断密码是否合法：
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return JsonResponse({'code': 400,
                                      'errmsg': '请输入8-20位的密码'})

        #判断验证码是否一致


        # 1:获取redis连接对象
        redis_conn = get_redis_connection("verify_code")

        # 2:根据电话在redis数据库中获取sms_code，验证码
        sms_code_server = redis_conn.get("sms_%s"% mobile)

        # 3:如果获取的验证码不存在
        if not sms_code_server :
            return JsonResponse({
                'code': 400,
                'errmsg': "验证码失效",
            })

        # 4:如果用户输入的验证码和redis缓存中存的不一样(redis数据库读的是字节)
        if sms_code_client != sms_code_server.decode():
            return JsonResponse({
                "code": 400,
                "errmsg": "用户验证码输入有误"
            })

        # 判断access_token是否是伪造的。
        #对access_token进行解密，获取openid,如果解密出现问题，则是用户伪造的数据，如果解密正常再判断是否用户是否存在。
        openid =  SecretOauth().loads(access_token).get("openid")
        if not openid:
            return JsonResponse({
                "code": 400,
                "errmsg" : "用户的accesstoken解密失败"
            })


        # 3：数据处理---根据mibile判断用户是否存在，如果存在绑定他的openid,如果不存在新建用户，写入数据库。

        # 3.1： 根据电话获取User对象
        try:
            user = User.objects.get(mobile=mobile)
        except Exception as e:
            print(e)
            # 用户不存在，新建用户
            user = User.objects.create_user(
                username=mobile,
                password= password,
                mobile = mobile,
            )
        # 如果用户存在，先检查密码是否正确
        else:
            if not user.check_password(password):
                JsonResponse({
                    "code": 400,
                    "errmsg": "密码输入错误"
                })

        # 现在确定用户是存在的，且密码正确，需要绑定opneid
        # 绑定openid
        OAuthQQUser.objects.create(openid= openid, user=user)

        # 状态保持
        login(request,user)

        # 构建响应返回
        response = JsonResponse({
            "code": 0,
            "errmsg": "ok"
        })

        response.set_cookie("username", user.username, max_age=3600*24*14)

        request.user = user
        return merge_cart_cookie_to_redis(request, response)























